use super::utils::{generate_err, generate_ok};
use crate::models::DbState;
use crate::utils::env_db_name;
use actix_web::{delete, get, http::StatusCode, post, web, HttpRequest, HttpResponse, Responder};
use chrono::Utc;
use futures_util::StreamExt;
use mongodb::{
    bson::{doc, oid::ObjectId, Document},
    Cursor,
};
use serde::Deserialize;
use serde_json::json;

const COLLECTION_NAME: &str = "markdowns";
#[derive(Deserialize)]
struct MarkdownData {
    title: String,
    content: String,
    id: Option<String>,
}

#[post("/markdown")]
pub async fn save_markdown(
    _req: HttpRequest,
    state: web::Data<DbState>,
    payload: web::Json<MarkdownData>,
) -> impl Responder {
    let collection = state
        .client
        .database(&env_db_name())
        .collection(COLLECTION_NAME);

    let now = Utc::now();

    if let Some(noteId) = &payload.id{

        let object_id = match ObjectId::parse_str(&noteId) {
            Ok(id) => id,
            Err(_) => return generate_err(&format!("id format is wrong:{}",noteId)),
        };
        let filter = doc! {
            "_id": object_id
        };
        let update = doc! {
            "$set": {"title": payload.title.clone(), "content": payload.content.clone(), "updated_at": now.to_rfc3339()}
        };
        let result = collection.find_one_and_update(filter, update).await;

        match result {
            Ok(_) => generate_ok(json!({
                "id":payload.id
            })),
            Err(e) => generate_err(&format!("{:?}", e)),
        }
    } else {
        let document = doc! {
            "title": payload.title.to_string(),
            "content": payload.content.to_string(),
            "created_at": now.to_rfc3339()
        };
        let result = collection.insert_one(document).await;

        match result {
            Ok(insert_result) => generate_ok(json!({
                "id": insert_result
                .inserted_id
                .as_object_id()
                .expect("inserted_id error")
                .to_hex()

            })),
            Err(e) => generate_err(&format!("{:?}", e)),
        }
    }
}
#[delete("/markdown/{id}")]
pub async fn delete_markdown(
    _req: HttpRequest,
    state: web::Data<DbState>,
    id: web::Path<String>,
) -> impl Responder {
    let collection = state
        .client
        .database(&env_db_name())
        .collection::<Document>(COLLECTION_NAME);

    let id_str = id.into_inner();

    let object_id = match ObjectId::parse_str(&id_str) {
        Ok(id) => id,
        Err(_) => return generate_err(&format!("id format is wrong:{}", id_str)),
    };

    let filter = doc! {"_id": object_id};
    let result = collection.delete_one(filter).await;

    match result {
        Ok(delete_result) => generate_ok(json!({
            "deleted_count": delete_result.deleted_count
        })),
        Err(error) => generate_err(&error.to_string()),
    }
}
#[get("/markdown/{id}")]
pub async fn get_markdown(
    _req: HttpRequest,
    state: web::Data<DbState>,
    id: web::Path<String>,
) -> impl Responder {
    let collection = state
        .client
        .database(&env_db_name())
        .collection::<Document>(COLLECTION_NAME);

    let id_str = id.into_inner();

    let object_id = match ObjectId::parse_str(&id_str) {
        Ok(id) => id,
        Err(_) => return generate_err(&format!("id format is wrong:{}", id_str)),
    };

    let filter = doc! {"_id": object_id};
    let result = collection.find_one(filter).await;

    match result {
        Ok(valid_result) => generate_ok(json!({
            "content": valid_result.expect("has no result").get_str("content").expect("get content error")
        })),
        Err(error) => generate_err(&error.to_string()),
    }
}

/// 获取所有Markdown的标题列表
#[get("/markdown_titles")]
pub async fn get_markdown_titles(req: HttpRequest, state: web::Data<DbState>) -> impl Responder {
    let collection = state
        .client
        .database(&env_db_name())
        .collection::<Document>(COLLECTION_NAME);

    let cursor: Cursor<Document> = match collection.find(Document::new()).await {
        Ok(cursor) => cursor,
        Err(e) => return generate_err(&format!("Database query failed: {:?}", e)),
    };

    // 使用StreamExt特性，collect可以直接将流转换为集合
    let titles: Vec<Result<serde_json::Value, mongodb::error::Error>> = cursor
        .map(|doc_result| {
            let doc = doc_result?;
            let title = doc
                .get_str("title")
                .map_err(|e| {
                    mongodb::error::Error::custom(format!("Mongodb get title error:{:?}", e))
                })?
                .to_string();
            let id = doc
                .get("_id")
                .and_then(|id_value| id_value.as_object_id())
                .map(|object_id| object_id.to_hex())
                .ok_or_else(|| mongodb::error::Error::custom("Missing or invalid _id field"))?
                .to_string();

            Ok(json!({"title": title, "id": id}))
        })
        .collect()
        .await;

    // 处理可能的错误，并转换为JSON响应
    let titles: Vec<serde_json::Value> = titles.into_iter().filter_map(Result::ok).collect();

    generate_ok(json!({ "list": titles }))
}
